
package com.tgh.utils;

import android.opengl.GLES20;
import android.util.Log;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import java.util.ArrayList;
import java.util.List;

public class GLTriangleBatch {
	
	
    public GLTriangleBatch() {
        mVertices=new ArrayList<Vector3f>();
        mNormals=new ArrayList<Vector3f>();
        mTextures=new ArrayList<Vector2f>();
        mIndices=new ArrayList<Short>();
    }

    public boolean loadDataFromSD(String cacheName) {
        if (cacheName == null) {
            return false;
        }
        File dir=new File("mnt/sdcard/gldata");
        if (!dir.exists()) {
            dir.mkdirs();
        }
        File verticeFile = new File(dir, cacheName+"V.dat");
        File normalFile = new File(dir, cacheName+ "N.dat");
        File textureFile = new File(dir, cacheName+ "T.dat");
        File indicesFile = new File(dir, cacheName+ "I.dat");
        ArrayList<Vector3f> vertices = readFromSD(verticeFile);
        ArrayList<Vector3f> normals = readFromSD(normalFile);
        ArrayList<Vector2f> textures = readFromSD(textureFile);
        ArrayList<Short> indices = readFromSD(indicesFile);

        if (vertices == null || normals == null || textures == null || indices == null) {
            return false;
        }
        mVertices.clear();
        mVertices.addAll(vertices);
        
        mNormals.clear();
        mNormals.addAll(normals);
        
        mTextures.clear();
        mTextures.addAll(textures);
        
        mIndices.clear();
        mIndices.addAll(indices);
        
        end();
        return true;
    }
    
    public void cacheDataToSD(String cacheName) {
        if (cacheName!=null) {
            File dir=new File("mnt/sdcard/gldata");
            if (!dir.exists()) {
                dir.mkdirs();
            }
            File verticeFile = new File(dir, cacheName+"V.dat");
            File normalFile = new File(dir, cacheName+ "N.dat");
            File textureFile = new File(dir, cacheName+ "T.dat");
            File indicesFile = new File(dir, cacheName+ "I.dat");
            writeToSD(verticeFile, mVertices);
            writeToSD(normalFile, mNormals);
            writeToSD(textureFile, mTextures);
            writeToSD(indicesFile, mIndices);
        }
    }
    /**
     * 添加一个三角形，三个顶点为逆时针顺序
     * @param v1
     * @param v2
     * @param v3
     */
    public void addTriangle(Vector3f[] vertices, Vector3f[] normals, Vector2f[] textures) {
    	for(int i=0;i<3;i++){
    		
    		final Vector3f vect=vertices[i];
    		formatVector3f(vect);
    		
    		final Vector3f normal=normals[i];
    		normal.normalize();
    		formatVector3f(normal);
    		
    		final Vector2f texture=textures[i];
    		
    	  	short index = (short) mVertices.indexOf(vect);
    	  	
    	  	if ( (index!=-1) && (mNormals.indexOf(normal)!=-1) && (mTextures.indexOf(texture)!=-1) ) {
    	  	  mIndices.add(index);
            }else {
    			mVertices.add(vect);
    			mNormals.add(normal);
    			mTextures.add(textures[i]);
    			index=(short) (mVertices.size()-1);
    			mIndices.add(index);
    		}
    	}
    }
    
    public void end() {
        float[] vertices = convertVector3ToArray(mVertices);
        float[] normals = convertVector3ToArray(mNormals);
        float[] textures = convertVector2ToArray(mTextures);
        mVerticeBuffer = GLTools.makeFloatBuffer(vertices);
        mNormalBuffer = GLTools.makeFloatBuffer(normals);
        mTextureBuffer = GLTools.makeFloatBuffer(textures);
        short[] indices = convertShortList2Array(mIndices);
        mIndiceBuffer = GLTools.makeShortBuffer(indices);
        mLineBuffer = GLTools.convertTrianglesIndicesToLines(mIndices);
    }
    
    public void drawLines(boolean drawLines) {
        this.drawLines=drawLines;
    }
    public void copyVertexData(List<Vector3f> vertices) {
        mVertices.clear();
        mVertices.addAll(vertices);
    }
    public void copyNormalData(List<Vector3f> normals) {
        mNormals.clear();
        mNormals.addAll(normals);
    }
    public void copyTexturesData(List<Vector2f> textures) {
        mTextures.clear();
        mTextures.addAll(textures);
    }
    public void copyIndicesData(List<Short> indices) {
        mIndices.clear();
        mIndices.addAll(indices);
    }
    
    public void draw() {
        GLES20.glVertexAttribPointer(GLShaderManager.GL_ATTRIBUTE_VERTEX, 3, GLES20.GL_FLOAT, false, 0, mVerticeBuffer);
        GLES20.glEnableVertexAttribArray(GLShaderManager.GL_ATTRIBUTE_VERTEX);
        
        GLES20.glVertexAttribPointer(GLShaderManager.GL_ATTRIBUTE_NORMAL, 3, GLES20.GL_FLOAT, false, 0, mNormalBuffer);
        GLES20.glEnableVertexAttribArray(GLShaderManager.GL_ATTRIBUTE_NORMAL);
        
        GLES20.glVertexAttribPointer(GLShaderManager.GL_ATTRIBUTE_TEXTURE0, 2, GLES20.GL_FLOAT, false, 0, mTextureBuffer);
        GLES20.glEnableVertexAttribArray(GLShaderManager.GL_ATTRIBUTE_TEXTURE0);
        if (drawLines) {
            GLES20.glDrawElements(GLES20.GL_LINES, mLineBuffer.capacity(), GLES20.GL_UNSIGNED_SHORT, mLineBuffer);
        }else {
            GLES20.glDrawElements(GLES20.GL_TRIANGLES, mIndices.size(), GLES20.GL_UNSIGNED_SHORT, mIndiceBuffer);
        }
    }
    

    public List<Short> getIndices() {
        return mIndices;
    }
    
    private void writeToSD(File file,Object obj) {
        try {
            if (file.exists()) {
                file.delete();
            }
            FileOutputStream fos=new FileOutputStream(file);
            ObjectOutputStream oos=new ObjectOutputStream(fos);
            oos.writeObject(obj);
            oos.close();
        } catch (IOException e) {
            Log.e("test", e.getMessage());
        }
    }
    
    private <T> ArrayList<T> readFromSD(File file) {
        try {
            FileInputStream fis=new FileInputStream(file);
            ObjectInputStream ois=new ObjectInputStream(fis);
            @SuppressWarnings("unchecked")
            ArrayList<T> arrays=(ArrayList<T>) ois.readObject();
            ois.close();
            return arrays;
        } catch (Exception e) {
            Log.e("test", e.getMessage());
        }
        return null;
    }
    
    private void formatVector3f(Vector3f vect){
    	vect.x=formatFloat(vect.x);
    	vect.y=formatFloat(vect.y);
    	vect.z=formatFloat(vect.z);
    }
    
    private float formatFloat(float input) {
		return Math.round(input*ACCURACY)/ACCURACY;
	}
    
    private float[] convertVector3ToArray(List<Vector3f> vectors){
    	float[] array=new float[vectors.size()*3];
    	for(int i=0,size=vectors.size();i<size;i++){
    		final Vector3f vect=vectors.get(i);
    		array[i*3+0]=vect.x;
    		array[i*3+1]=vect.y;
    		array[i*3+2]=vect.z;
    	}
    	return array;
    }
    
    private float[] convertVector2ToArray(List<Vector2f> vectors){
    	float[] array=new float[vectors.size()*3];
    	for(int i=0,size=vectors.size();i<size;i++){
    		final Vector2f vect=vectors.get(i);
    		array[i*3+0]=vect.x;
    		array[i*3+1]=vect.y;
    	}
    	return array;
    }
    
    private short[] convertShortList2Array(List<Short> shorts) {
    	short[] array=new short[shorts.size()];
    	for (int i = 0; i < array.length; i++) {
    		array[i]=shorts.get(i);
		}
    	return array;
	}
    private boolean drawLines;
    private static final float ACCURACY=10000f;
    private ArrayList<Vector3f> mVertices;
    private ArrayList<Vector3f> mNormals;
    private ArrayList<Vector2f> mTextures;
    private ArrayList<Short> mIndices;
	private FloatBuffer mVerticeBuffer;
	private FloatBuffer mNormalBuffer;
	private ShortBuffer mIndiceBuffer;
	private FloatBuffer mTextureBuffer;
    private ShortBuffer mLineBuffer;
    
}
